/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sanger;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.*;
import java.io.*;
import java.util.*;

/**
 *
 * @author lorddoskias
 */
public class EC2Utilities {

    /**
     * Copy local file to a pre-defined remote directory on an ec2 instance
     * @param src - full path to local file
     * @throws IOException 
     */
    public static boolean copyFileToEC2(String src) throws IOException {


        String hostname = getInstanceDns(getInstanceIdFromTag("Name", "big instance"));
        String username = "ec2-user";

        File keyfile = new File(Constants.PRIVATE_KEY); // or "~/.ssh/id_dsa"
        String keyfilePass = "joespass"; // will be ignored if not needed

        try {

            Connection conn = new Connection(hostname);
            conn.connect();

            boolean isAuthenticated = conn.authenticateWithPublicKey(username, keyfile, keyfilePass);

            if (isAuthenticated == false) {
                throw new IOException("Authentication failed.");
            }


            SCPClient client = new SCPClient(conn);

            client.put(src, Constants.REMOTE_UPLOAD_DIR);
            /* Close the connection */

            conn.close();

        } catch (IOException e) {
            e.printStackTrace(System.err);
            return false;
        }

        return true;

    }

    /**
     * Starts an EC2 Instance 
     * @param id - id of the instance we want to start
     * @throws IOException
     * @throws InterruptedException  - thrown if thread is interrupted while waiting
     * for the instance to boot up
     */
    public static boolean startInstance(int id) throws IOException {


        AmazonEC2Client ec2;
        try {
            ec2 = Constants.getEC2Obj();
        } catch (IOException ex) {
            return false;
        }

        //we work in the EU region
        ec2.setEndpoint("ec2.eu-west-1.amazonaws.com");
        //list containing which instances to start
        List<String> instances = new ArrayList<String>();
        //take list of isntances
        DescribeInstancesResult res = ec2.describeInstances();
        //take the first instance
        instances.add(getInstanceIdFromTag("Name", "big instance"));
        //create a request object
        StartInstancesRequest req = new StartInstancesRequest();
        //asign list to request
        req.setInstanceIds(instances);

        //exec request
        ec2.startInstances(req);
        try {
            //polling based mechanism proved utter failure

            Thread.sleep(60 * 1000);
        } catch (InterruptedException ex) {
            return false;
        }

        return true;
    }

    /**
     * Get the dynamic DNS for an instance
     * @param id - the id of the instance whose DNS we want
     * @return string representing the dns name
     * @throws IOException 
     */
    private static String getInstanceDns(String id) throws IOException {

        AmazonEC2Client ec2 = Constants.getEC2Obj();
        //we work in the EU region
        ec2.setEndpoint("ec2.eu-west-1.amazonaws.com");
        DescribeInstancesResult res = ec2.describeInstances();

        List<Reservation> reservations = res.getReservations();

        for (Reservation reservation : reservations) {
            List<Instance> instances = reservation.getInstances();
            for (Instance instance : instances) {
                if (instance.getInstanceId().equals(id)) {
                    return instance.getPublicDnsName();
                }
            }
        }

        return null;
    }

    /**
     * Invokes a process on a remote EC2 instance
     * @throws IOException
     */
    public static boolean startRemoteProcess(String prefix, String filename, List<String> params) throws IOException {
        String hostname = getInstanceDns(getInstanceIdFromTag("Name", "big instance"));
        String username = "ec2-user";

        File keyfile = new File(Constants.PRIVATE_KEY);
        String keyfilePass = "joespass"; // will be ignored if not needed

        try {

            Connection conn = new Connection(hostname);
            conn.connect();

            boolean isAuthenticated = conn.authenticateWithPublicKey(username, keyfile, keyfilePass);

            if (isAuthenticated == false) {
                throw new IOException("Authentication failed.");
            }

            Session sess = conn.openSession();
            sess.execCommand(Constants.REMOTE_APP_DIR + " " //script to execute
                    + Constants.REMOTE_UPLOAD_DIR + "/" + filename + " " //first parameter - path to file for processing
                    + prefix + " " //second parameter - user dir to create
                    + params.get(0) + " " //email 1
                    + params.get(1) + " " //email 2
                    + params.get(2) + " " //hash value for velvetH
                    + params.get(3) // read type 
                    );

            InputStream stdout = new StreamGobbler(sess.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));


            while (true) {
                String line = br.readLine();
                if (line == null) {
                    break;
                }
                System.out.println(line);
            }

            /* Close this session */

            sess.close();

            /* Close the connection */

            conn.close();

        } catch (IOException e) {
            e.printStackTrace(System.err);
            return false;
        }

        return true;
    }

    public static String getInstanceIdFromTag(String tagName, String tagValue) throws IOException {

        AmazonEC2Client ec2 = Constants.getEC2Obj();
        ec2.setEndpoint("ec2.eu-west-1.amazonaws.com");

        DescribeInstancesResult res = ec2.describeInstances();

        List<Reservation> reservations = res.getReservations();

        for (Reservation reservation : reservations) {
            List<Instance> instances = reservation.getInstances();
            for (Instance instance : instances) {
                List<Tag> tags = instance.getTags();
                for (Tag tag : tags) {
                    if (tag.getKey().equals(tagName) && tag.getValue().equals(tagValue)) {
                        return instance.getInstanceId();

                    }
                }
            }
        }

        return null;
    }
}
